package com.hemj.common.utils.IdGenerator;


/**
 * SnowFlake算法 53位Long类型生成唯一ID:表示生成从时间起点开始68年的id数据。
 * 第一位0，表明正数
 * 2-33，31位，表示秒时间差值，起始值自定义
 * 33-37，5位。表示机器码，（21-16）
 * 38-53，16位，sequenceBits 序列号位移数 毫秒内计数器 本机内存生成，性能高
 */
public class IdGenerator {
    private Long beginTs = null;
    private Integer sequenceBits = null;
    private Integer timeBits = null;
    private Long sequenceMask = null;
    private Long processId = null;
    private Long lastTs = 0L;


    private Long sequence = 0L;

    public IdGenerator(long beginTs,  int sequenceBits, int timeBits, Long sequenceMask, Long processId) {
        this.beginTs = beginTs;
        this.sequenceBits = sequenceBits;
        this.timeBits = timeBits;
        this.sequenceMask = sequenceMask;
        this.processId = processId;
    }


    public synchronized long nextId() {
        long ts = timeGen();
        if (ts < lastTs) {// 刚刚生成的时间戳比上次的时间戳还小，出错
            throw new RuntimeException("时间戳顺序错误");
        }
        if (ts - lastTs < 1000) {// 刚刚生成的时间戳跟上次的时间戳一样，则需要生成一个sequence序列号
            // sequence循环自增
        	sequence = (sequence + 1) & sequenceMask;
            // 如果毫秒内序列溢出则需要重新生成时间戳
            if (sequence == 0) {
                // 且必须保证时间戳序列往后
                ts = nextTs(lastTs);
            }
        } else {// 如果ts>lastTs，时间戳序列已经不同了，此时可以不必生成sequence了，直接取0
            sequence = 0L;
        }

        lastTs = ts;// 更新lastTs时间戳
        long nextId = ((ts - beginTs)/1000 << timeBits) | (processId << sequenceBits) | sequence;
        return nextId;
    }

    private long timeGen() {
        return System.currentTimeMillis();
    }

    private long nextTs(long lastTs) {
        long ts = timeGen();
        while (ts - lastTs < 1000) {
            ts = timeGen();
        }
        return ts;
    }

}

